package com.slfx.open.api.interceptor;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.slfx.open.api.entity.AppSecret;
import com.slfx.open.api.sdk.common.exception.CommonException;
import com.slfx.open.api.sdk.common.exception.ErrorCodeEnum;
import com.slfx.open.api.sdk.utils.Common;
import com.slfx.open.api.sdk.utils.RsaUtils;
import com.slfx.open.api.service.AppSecretService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

/**
 * @author zengqingfa
 * @className InterceptorsConfigurer
 * @description
 * @create 2022/9/25 16:42
 */
@Component
@Slf4j
public class ApiRequestInterceptor extends HandlerInterceptorAdapter {

    @Resource
    private AppSecretService appSecretService;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handle) throws Exception {
        //获取请求头参数
        Map<String, String> headerMap = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            headerMap.put(name, request.getHeader(name));
        }
        //获取到appId、timestamp、sign,请求头参数上的字段名称不区分大小写
        String appId = headerMap.get("appid");
        String timeStamp = headerMap.get("timestamp");
        String sign = headerMap.get("sign");
        log.info("请求url:{},appid:{},timestamp:{},sign:{}", request.getRequestURI(), appId, timeStamp, sign);
        //校验参数不能为空
        if (StringUtils.isBlank(appId)) {
            throw new CommonException(ErrorCodeEnum.ERROR_APP_ID_IS_NOT_EMPTY);
        }
        if (StringUtils.isBlank(timeStamp)) {
            throw new CommonException(ErrorCodeEnum.ERROR_TIME_STAMP_NOT_EMPTY);
        }
        if (StringUtils.isBlank(sign)) {
            throw new CommonException(ErrorCodeEnum.ERROR_SIGN_IS_NOT_EMPTY);
        }
        //校验appId
        AppSecret appSecret = appSecretService.getOne(new LambdaQueryWrapper<AppSecret>()
                .eq(AppSecret::getAppId, headerMap.get("appid"))
                .last("limit 1"));
        if (Objects.isNull(appSecret)) {
            throw new CommonException(ErrorCodeEnum.ERROR_APP_ID_IS_NOT_EMPTY);
        }
        //时间戳校验，防dos攻击
        Long time;
        try {
            time = Long.parseLong(timeStamp);
        } catch (NumberFormatException e) {
            setResponse(response, "时间戳格式异常");
            return false;
        }
        long currentTimeMillis = System.currentTimeMillis();
        log.info("time:{},currentTimeMillis:{}", time, currentTimeMillis);
        //(6000000/1000)s=6000s /60 =100minute
        if (Math.abs(time - currentTimeMillis) > 6000000) {
            setResponse(response, "时间戳过期");
            return false;
        }
        String requestURI = request.getRequestURI();
        String serverName = request.getServerName();//主机地址
        int port = request.getServerPort();//端口号
        String path = request.getContextPath();//带斜杠的项目名
        String queryString = request.getQueryString();//获取请求参数字符串
        //拼接对应的url
        String url = serverName + ":" + port + path + requestURI + queryString;
        //获取请求参数map
        SortedMap<String, String> sortMap = new TreeMap<>();
        //先判断是否是post请求
        String contentType = request.getContentType();
        try {
            if (contentType != null && contentType.indexOf("json") != -1 && "post".equalsIgnoreCase(request.getMethod())) {
                //获取到请求参数 request是经过包装的MyHttpServletRequestWrapper
                String json = IOUtils.toString(request.getInputStream(), "utf-8");
                sortMap.put("bizContent", json);
            } else {
                //获取到get请求上的参数
                Enumeration<String> params = request.getParameterNames();
                while (params.hasMoreElements()) {
                    String name = params.nextElement();
                    sortMap.put(name, request.getParameter(name));
                }
            }
        } catch (Exception e) {
            log.error("参数解析失败，参数不能为空", e);
            setResponse(response, "参数解析失败，参数不能为空");
            return false;
        }
        log.debug("第三方请求参数:{},签名signature:{}", JSON.toJSONString(sortMap), sign);
        if (sortMap == null || sortMap.size() == 0) {
            setResponse(response, "请求参数为空");
            return false;
        }
        String dataStr = Common.forInSpiry(sortMap, appId, timeStamp);
        byte[] decode = Base64.getDecoder().decode(sign);
        //校验签名
        boolean verify = RsaUtils.verify(dataStr.getBytes(), decode, RsaUtils.getPublicKeyByStr(appSecret.getPublicKey()));
        log.info("请求url:{},appid:{},timestamp:{},sign:{},签名校验结果：{}", request.getRequestURI(), appId, timeStamp, sign, verify);
        if (!verify) {
            log.error("平台签名错误,sign:{}", sign);
            setResponse(response, "平台签名错误");
            return false;
        }
        return super.preHandle(request, response, handle);
    }


    @SuppressWarnings("all")
    private void setResponse(HttpServletResponse response, String errorMessage) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println(JSON.toJSONString(errorMessage));
        writer.flush();
        writer.close();
    }
}
